/*	
*	File: main.cpp
*	Date: 2011/11/01
*	User: Ronmaru
*	Desctiption: Main file parse command line and call functionality
*/

#include "pcraft-tool.h"

#include <iostream>
#include <string>

using namespace std;
namespace po = boost::program_options;

int main(int argc, char *argv[])
{
  // Declare the supported options
  po::options_description options_desc("Allowed options");
  options_desc.add_options()
    ("help", "produce help message")

    ("get-list-of-devices", "writes list of devices to devices.txt")

    ("packet-number", po::value<int>()->default_value(1), "number packets to send")
    ("interface-number", po::value<int>()->default_value(1), "number of interface")
    //("destination", po::value<string>()->default_value("127.0.0.1"), "")
    //("source", po::value<string>()->default_value("127.0.0.1"), "")

    ("ethernet", "ethernet mode")
    ("ethernet-destination", po::value<string>()->default_value("ff:ff:ff:ff:ff:ff"), "")
    ("ethernet-source", po::value<string>()->default_value("ff:ff:ff:ff:ff:ff"), "")
    ("ethernet-type", po::value<int>()->default_value(0), "")

    ("ipv4", "ip mode")
    ("ipv4-version", po::value<int>()->default_value(4), "version of ip protocol")
    ("ipv4-header-length", po::value<int>()->default_value(5), "")
    ("ipv4-type-of-service", po::value<int>()->default_value(0), "")
    ("ipv4-total-length", po::value<int>()->default_value(5), "")
    ("ipv4-identification", po::value<int>()->default_value(1234), "")
    ("ipv4-dont-fragment", po::value<int>()->default_value(0), "")
    ("ipv4-more-fragments", po::value<int>()->default_value(0), "")
    ("ipv4-fragment-offset", po::value<int>()->default_value(0), "")
    ("ipv4-ttl", po::value<int>()->default_value(128), "")
    ("ipv4-protocol", po::value<int>()->default_value(4), "")
    ("ipv4-source-addr", po::value<string>()->default_value("127.0.0.1"), "")
    ("ipv4-dest-addr", po::value<string>()->default_value("127.0.0.1"), "")
    ("ipv4-body", po::value<string>()->default_value(""), "")

    ("icmp", "icmp mode")
    ("icmp-type", po::value<int>()->default_value(0), "")
    ("icmp-code", po::value<int>()->default_value(0), "")
    ("icmp-identifier", po::value<int>()->default_value(1111), "")
    ("icmp-sequence-number", po::value<int>()->default_value(0), "")
    ("icmp-body", po::value<string>()->default_value(""), "")

    ("udp", "udp mode")
    ("udp-source-port", po::value<int>()->default_value(11111), "")
    ("udp-dest-port", po::value<int>()->default_value(22222), "")
    ("udp-message-length", po::value<int>()->default_value(8), "")
    ("udp-body", po::value<string>()->default_value(""), "")

    ("tcp", "tcp mode")
    ("tcp-source-port", po::value<int>()->default_value(11111), "")
    ("tcp-dest-port", po::value<int>()->default_value(22222), "")
    ("tcp-seq-number", po::value<int>()->default_value(12345), "")
    ("tcp-ack-number", po::value<int>()->default_value(12346), "")
    ("tcp-data-offset", po::value<int>()->default_value(5), "")
    ("tcp-urg", po::value<bool>()->default_value(false), "")
    ("tcp-ack", po::value<bool>()->default_value(false), "")
    ("tcp-psh", po::value<bool>()->default_value(false), "")
    ("tcp-rst", po::value<bool>()->default_value(false), "")
    ("tcp-syn", po::value<bool>()->default_value(false), "")
    ("tcp-fin", po::value<bool>()->default_value(false), "")
    ("tcp-window", po::value<int>()->default_value(0), "")
    ("tcp-urgent-point", po::value<int>()->default_value(0), "")
    ("tcp-message-length", po::value<int>()->default_value(0), "")
    ("tcp-body", po::value<string>()->default_value(""), "")

    ("igmpv2", "igmp mode")
    ("igmpv2-type", po::value<int>()->default_value(0x16), "")
    ("igmpv2-max-resp-time", po::value<int>()->default_value(0), "")
    ("igmpv2-group-address", po::value<string>()->default_value("127.0.0.1"), "")

    ("arp", "arp mode")
    ("arp-hardware-type", po::value<int>()->default_value(1), "")
    ("arp-protocol-type", po::value<int>()->default_value(2048), "")
    ("arp-hardware-length", po::value<int>()->default_value(6), "")
    ("arp-protocol-length", po::value<int>()->default_value(4), "")
    ("arp-operation", po::value<int>()->default_value(1), "")
    ("arp-sender-haddr", po::value<string>()->default_value("00:00:00:00:00:00"), "")
    ("arp-sender-paddr", po::value<string>()->default_value("127.0.0.1"), "")
    ("arp-target-haddr", po::value<string>()->default_value("00:00:00:00:00:00"), "")
    ("arp-target-paddr", po::value<string>()->default_value("127.0.0.1"), "")

    ("rip", "rip mode")
    ("rip-command", po::value<int>()->default_value(1), "")
    ("rip-routing-domain", po::value<int>()->default_value(1), "")
    ("rip-af-ident", po::value<int>()->default_value(2), "")
    ("rip-route-tag", po::value<int>()->default_value(0), "")
    ("rip-ip-addr", po::value<string>()->default_value("127.0.0.1"), "")
    ("rip-mask", po::value<string>()->default_value("255.255.255.0"), "")
    ("rip-next-hop", po::value<string>()->default_value("127.0.0.2"), "")
    ("rip-metric", po::value<int>()->default_value(16), "")
    ;

  po::variables_map var_map;
  po::store(po::parse_command_line(argc, argv, options_desc), var_map);
  po::notify(var_map); 

  int packet_number = var_map["packet-number"].as<int>();

  if (var_map.count("help")) {

    cout << options_desc << endl;
  } else if (var_map.count("get-list-of-devices")) {
    
    WriteDevicesList(string("devices.txt"));

  } else if (var_map.count("ethernet")) {
    
    ETHERNETpacket ethernet_packet(MakeEthernetHeader(var_map), var_map["interface-number"].as<int>());
    for (int i = 0; i < packet_number; ++i)
      ethernet_packet.send();

  } else if (var_map.count("ipv4")) {

    boost::asio::io_service io_service;
    IPV4packet ipv4_packet(io_service, MakeIpv4Header(var_map), var_map["ipv4-body"].as<string>());
    for (int i = 0; i < packet_number; ++i)
      ipv4_packet.send();
    io_service.run();

  } else if (var_map.count("icmp")) {

    boost::asio::io_service io_service;
    ICMPpacket *icmp_packet = NULL;
    icmp_packet = new ICMPpacket(io_service, MakeIpv4Header(var_map), MakeIcmpHeader(var_map),
      var_map["icmp-body"].as<string>());

    for (int i = 0; i < packet_number; ++i)
      icmp_packet->send();
    io_service.run();

    if (icmp_packet)
      delete icmp_packet;

  } else if (var_map.count("igmpv2")) {

    boost::asio::io_service io_service;
    IGMPv2packet *igmpv2_packet = NULL;

    igmpv2_packet = new IGMPv2packet(io_service, MakeIpv4Header(var_map), MakeIgmpv2Header(var_map));

    for(int i = 0; i < packet_number; ++i)
      igmpv2_packet->send();
    io_service.run();

    if (igmpv2_packet)
      delete igmpv2_packet;

  } else if (var_map.count("udp")) {

    boost::asio::io_service io_service;
    UDPpacket *udp_packet = NULL;

    udp_packet = new UDPpacket(io_service, 
      MakeIpv4Header(var_map), MakeUdpHeader(var_map), MakeUdpPseudoHeader(var_map),
      var_map["udp-body"].as<string>());

    for (int i = 0; i < packet_number; ++i)
      udp_packet->send();
    io_service.run();
     
    if (udp_packet)
      delete udp_packet;

  } else if (var_map.count("arp")) {

    ARPpacket arp_packet(MakeEthernetHeader(var_map), MakeArpHeader(var_map), 
      var_map["interface-number"].as<int>());
    for (int i = 0; i < packet_number; ++i)
      arp_packet.send();

  } else if (var_map.count("tcp")) {

    TCPpacket *tcp_packet = NULL;

    tcp_packet = new TCPpacket(MakeEthernetHeader(var_map), 
      MakeIpv4Header(var_map), MakeTcpHeader(var_map), MakeTcpPseudoHeader(var_map),
      var_map["tcp-body"].as<string>(), var_map["interface-number"].as<int>());

    for (int i = 0; i < packet_number; ++i)
      tcp_packet->send();

    if (tcp_packet)
      delete tcp_packet;

  } else if (var_map.count("rip")) {

    boost::asio::io_service io_service;
    RIPpacket *rip_packet = NULL;

    rip_packet = new RIPpacket(io_service, 
      MakeIpv4Header(var_map), MakeUdpHeader(var_map), 
      MakeUdpPseudoHeader(var_map), MakeRipHeader(var_map));

    for (int i = 0; i < packet_number; ++i)
      rip_packet->send();
    io_service.run();

    if (rip_packet)
      delete rip_packet;

  }

  //::system("pause");

	return 0;
}